전체 블로그

// AI 에이전트 가이드

Cursor 로 세금계산서 자동 분개 — 80줄 만에

Cursor 에 headless MCP 를 붙이면 홈택스 매출 세금계산서를 받아 차변·대변까지 자동으로 끊는다. 셋업부터 분개 스크립트까지.

·headless

매월 부가세 신고 전, 누군가 홈택스에서 매출 세금계산서를 내려받아 한 건씩 분개를 끊는다. 같은 일을 Cursor 안에서 부탁하면 80줄짜리 스크립트 하나가 대신 끊는다.

이 글은 Cursor 에 headless MCP 를 붙이고, 매출 세금계산서를 받아 분개 전표까지 만든다. 셋업 약 10분. 분개 로직은 회사 규칙에 맞춰 한 번만 손보면 끝이다.

누가 이 글을 읽으면 좋을까

  • 부가세·결산 때 세금계산서를 수기로 분개하는 회계 담당
  • 경리 SaaS 에 분개 자동화를 붙이려는 개발자
  • 사전 지식: Cursor, headless 계정, 분개 대상 사업자의 공동인증서

무엇을 만들 것인가 (5초 미리보기)

Cursor 채팅에서:

지난달 매출 세금계산서 받아서 분개 전표로 끊어줘

# 잠시 후 …
세금계산서 23건 → 전표 23건.
2026-04-30 ㈜에이클라이언트  (차) 외상매출금 1,100,000 / (대) 제품매출 1,000,000, 부가세예수금 100,000

journal-2026-04.csv 로 저장 완료.

1. 준비

headless 콘솔에서 API key 를 발급하고, 분개 대상 사업자의 공동인증서를 한 번 등록한다. 인증서 한 건이면 홈택스가 자동으로 매칭된다.

bash
export H6S_API_KEY=h6s_live_...

2. Cursor 에 MCP 붙이기

Cursor 의 MCP 설정에 headless 진입점을 추가한다. ~/.cursor/mcp.json:

json
{
  "mcpServers": {
    "h6s": {
      "command": "npx",
      "args": ["-y", "@h6s-ai/cli", "mcp"],
      "env": { "H6S_API_KEY": "h6s_live_..." }
    }
  }
}

Cursor 를 한 번 재시작하면 h6s_* 도구가 채팅에서 자연어로 호출된다. 첫 호출은 npm cache 채우느라 1~2분 걸릴 수 있다. 미리 npm i -g @h6s-ai/cli 로 깔아두면 회피된다.

3. 세금계산서 받기

매출 세금계산서의 데이터 형식 ID 는 hometax.tax-invoices.sales.v1 다. 35개 필드가 고정이라 분개에 필요한 것만 골라 쓰면 된다 — 작성일자, 공급가액, 세액, 합계금액, 거래처 상호·사업자번호. 전체 필드는 /schemas/hometax.tax-invoices.sales.v1 응답에서 확인한다.

Cursor 에 자연어로 부탁하면 내부에서 h6s_fetch_data 가 호출된다.

지난달 매출 세금계산서 받아줘

4. 분개 — 80줄 스크립트

받은 세금계산서를 회사 계정과목 규칙에 맞춰 전표로 바꾼다. 핵심은 규칙 한 덩어리와 매핑 한 덩어리다.

typescript
type TaxInvoice = {
  writtenDate: string;       // 작성일자
  supplyAmount: number;      // 공급가액
  taxAmount: number;         // 세액
  totalAmount: number;       // 합계금액
  counterpartyName: string;  // 거래처 상호
  counterpartyBrn: string;   // 거래처 사업자번호
};

type Line = { account: string; debit: number; credit: number };

// 회사 규칙: 외상매출 기준. 현금매출이면 차변 계정만 바꾼다.
function toJournal(inv: TaxInvoice): Line[] {
  return [
    { account: "외상매출금", debit: inv.totalAmount, credit: 0 },
    { account: "제품매출", debit: 0, credit: inv.supplyAmount },
    { account: "부가세예수금", debit: 0, credit: inv.taxAmount },
  ];
}

function assertBalanced(lines: Line[]) {
  const d = lines.reduce((s, l) => s + l.debit, 0);
  const c = lines.reduce((s, l) => s + l.credit, 0);
  if (d !== c) throw new Error(`차대 불일치: ${d} vs ${c}`);
}

async function main() {
  const raw = await fetch("https://api.h6s.ai/api/v1/data-jobs/" + process.env.JOB_ID + "/results", {
    headers: { Authorization: `Bearer ${process.env.H6S_API_KEY}` },
  }).then((r) => r.json());

  const rows: string[] = ["date,counterparty,account,debit,credit"];
  for (const inv of raw.records as TaxInvoice[]) {
    const lines = toJournal(inv);
    assertBalanced(lines);
    for (const l of lines) {
      rows.push(
        [inv.writtenDate, inv.counterpartyName, l.account, l.debit, l.credit].join(","),
      );
    }
  }
  await Bun.write(`journal-${rows.length}.csv`, rows.join("\n"));
}

main();

assertBalanced 로 전표마다 차변 합과 대변 합을 맞춰본다. 분개 자동화에서 가장 자주 깨지는 지점이라 루프 안에서 매번 확인한다.

회사마다 계정과목이 다르니 toJournal 하나만 회사 규칙으로 바꾸면 된다. 현금매출·면세·영세율은 분기 한 줄로 갈라진다. 이 규칙을 Cursor 에 말로 설명하면 함수 본문을 대신 고쳐준다.

5. 자주 만나는 막힘

증상원인대응
도구가 안 보임MCP 등록 후 미재시작Cursor 재시작
첫 호출이 멈춤npm cache hydrationnpm i -g @h6s-ai/cli 선설치
failureCategory: CREDENTIAL인증서 만료·미등록콘솔에서 자격증명 갱신
차대 불일치 예외면세·영세율을 일반 규칙으로 처리toJournal 에 과세유형 분기 추가
거래처 누락수정세금계산서·합계표 혼입매출분(sales.v1)만 받는지 확인

더 깊이

분개가 한 번 끊기기 시작했다면 다음은 같은 headless API 를 다른 에이전트에서 쓰는 쪽이다. Cursor 연동 문서에 설치·자격증명·트러블슈팅이 한곳에 있다.